package ws.jonas.hoarder;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Random;

import ws.jonas.common.config.Config;
import ws.jonas.common.log.Logger;
import ws.jonas.common.model.Product;
import ws.jonas.common.model.Quantity;
import ws.jonas.common.model.Store;
import ws.jonas.common.web.WebQuerier;
import ws.jonas.hoarder.db.MssqlDb;
import ws.jonas.hoarder.db.MysqlDb;
import ws.jonas.hoarder.db.SqlDb;

public class Scraper {
	private static final Logger log = Logger.getInstance(Scraper.class);
	private SqlDb db;
	
	public static void main(String[] args) {
		if (args.length > 0) {
			log.info("Ignoring command line parameters (no options available)");
		}
		try {
			new Scraper().run();
		} catch (Exception e) {
			//Quit
		}
	}
	
	public void run() {
		try {
			Config.updateConfig();
			
			if (Config.get(Config.DB_VENDOR_KEY).equalsIgnoreCase("mysql")) {
				db = new MysqlDb();
			} else if (Config.get(Config.DB_VENDOR_KEY).equalsIgnoreCase("mssql")) {
				db = new MssqlDb();
			} else {
				log.severe("Invalid database vendor: " + Config.get(Config.DB_VENDOR_KEY));
				return;
			}
			
			scrape();
		} catch (SQLException e) {
			
		} catch (IOException e) {
			
		} catch (ClassNotFoundException e) {
			
		} finally {
			log.sendMails();
		}
	}
	
	private void scrape() {
		ArrayList<String> prodnrs = readProdnrsFromFile();
		for (int i = 0; i < prodnrs.size(); ++i) {
			String prodnr = prodnrs.get(i);
			WebQuerier web = null;
			try {
				web = new WebQuerier(prodnr);
			} catch (NumberFormatException e) {
				log.warning("Failed to parse prodnr: " + prodnr + ", skipping");
				continue;
			}
			
			Product product = web.query();
			if (product == null) {
				continue;
			}
			
			boolean productsAdded = false;
			for (Store store : product) {
				try {
					db.addStoreIfNotExists(store.getCity(), store.getAddress(), store.getCounty());
				} catch (SQLException e) {
					log.severe("Could not add store: city=" + store.getCity() + ", address=" + store.getAddress() + ", county=" + store.getCounty());
					log.severe(e);
				}
				
				for (Quantity quantity : store) {
					if (!productsAdded) {
						try {
							db.addProductIfNotExists(product.getProdnr(), product.getName(), quantity.getVolume());
						} catch (SQLException e) {
							log.severe("Could not add product: prodnr=" + product.getProdnr() + ", name=" + product.getName() + ", volume=" + quantity.getVolume());
							log.severe(e);
						}
					}
					
					try {
						db.addStock(product.getProdnr(), product.getName(), quantity.getVolume(), store.getCounty(), store.getCity(), store.getAddress(), quantity.getQuantity());
					} catch (SQLException e) {
						log.severe("Could not add stock: prodnr=" + product.getProdnr() + ", name=" + product.getName() + ", volume=" + quantity.getVolume() + ", city=" + store.getCity() + ", address=" + store.getAddress() + ", county=" + store.getCounty() + ", quantity=" + quantity.getQuantity());
						log.severe(e);
					}
				}
				productsAdded = true;
			}
			
			if (i != prodnrs.size() - 1) { //Dont bother sleeping if last iteration
				Random rnd = new Random();
				try {
					long sleepTime = 0;
					try {
						int queryMs = Integer.parseInt(Config.get(Config.QUERY_MS_KEY));
						int queryDeviationMs = Integer.parseInt(Config.get(Config.QUERY_DEVIATION_MS_KEY));
						if (queryMs != 0) {
							if (queryDeviationMs != 0) {
								sleepTime = queryMs - queryDeviationMs + rnd.nextInt(queryDeviationMs) * 2;
							} else {
								sleepTime = queryMs;
							}
						}
					} catch (NumberFormatException e) {
						log.warning("Failed to parse query sleep times, taking default value");
						sleepTime = Integer.parseInt(Config.getDefault(Config.QUERY_MS_KEY)) - Integer.parseInt(Config.getDefault(Config.QUERY_DEVIATION_MS_KEY)) + rnd.nextInt(Integer.parseInt(Config.getDefault(Config.QUERY_DEVIATION_MS_KEY)) * 2);
					}
					if (sleepTime > 0) {
						log.fine("Sleeping for " + (double)sleepTime / 1000 + " seconds");
						Thread.sleep(sleepTime);
					}
				} catch (InterruptedException e) {
					log.warning(e);
					Thread.currentThread().interrupt();
				}
			}
		}
	}
	
	private ArrayList<String> readProdnrsFromFile() {
		BufferedReader fileIn = null;
		ArrayList<String> ret = new ArrayList<String>();
		try {
			fileIn = new BufferedReader(new FileReader(Config.get(Config.PRODNR_FILE_KEY)));
			String line = null;
			while ((line = fileIn.readLine()) != null) {
				if (line.startsWith("#") || line.equals("")) {
					continue;
				}
				if (line.indexOf("#") != -1) {
					line = line.substring(0, line.indexOf("#")).trim();
				}
				log.fine("Adding prodnr " + line + " to query list");
				ret.add(line);
			}
		} catch (IOException e) {
			log.severe("Could not find/read prodnr file (" + new File(Config.get(Config.PRODNR_FILE_KEY)).getAbsolutePath() + "): " + e);
		} finally {
			try {
				if (fileIn != null) {
					fileIn.close();
				}
			} catch (IOException e) {
				log.warning(e);
			}
		}
		return ret;
	}
}
